D:\a\tools.proto\tools.proto\compiler\src\compiler\message.rs
Line | Count | Source |
1 | | // Copyright (c) 2025, BlockProject 3D |
2 | | // |
3 | | // All rights reserved. |
4 | | // |
5 | | // Redistribution and use in source and binary forms, with or without modification, |
6 | | // are permitted provided that the following conditions are met: |
7 | | // |
8 | | // * Redistributions of source code must retain the above copyright notice, |
9 | | // this list of conditions and the following disclaimer. |
10 | | // * Redistributions in binary form must reproduce the above copyright notice, |
11 | | // this list of conditions and the following disclaimer in the documentation |
12 | | // and/or other materials provided with the distribution. |
13 | | // * Neither the name of BlockProject 3D nor the names of its contributors |
14 | | // may be used to endorse or promote products derived from this software |
15 | | // without specific prior written permission. |
16 | | // |
17 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
18 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
19 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
20 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
21 | | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
22 | | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
23 | | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
24 | | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
25 | | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
26 | | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
27 | | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | | |
29 | | use crate::compiler::builder::FieldBuilder; |
30 | | use crate::compiler::error::Error; |
31 | | use crate::compiler::structure::{FixedFieldType, Structure}; |
32 | | use crate::compiler::union::Union; |
33 | | use crate::compiler::util::objects::name_index; |
34 | | use crate::compiler::util::types::{Name, PtrKey}; |
35 | | use crate::compiler::Protocol; |
36 | | use crate::model::message::MessageFieldValue; |
37 | | use crate::model::protocol::{Description, Endianness}; |
38 | | use crate::model::structure::StructFieldRaw; |
39 | | use bp3d_debug::{error, trace}; |
40 | | use std::cell::Cell; |
41 | | use std::fmt::{Display, Formatter}; |
42 | | use std::rc::Rc; |
43 | | |
44 | | #[derive(Clone, Debug)] |
45 | | pub enum Referenced { |
46 | | Struct(Rc<Structure>), |
47 | | Message(Rc<Message>), |
48 | | } |
49 | | |
50 | | impl Name for Referenced { |
51 | 37 | fn name(&self) -> &str { |
52 | 37 | match self { |
53 | 27 | Referenced::Struct(v) => &v.name, |
54 | 10 | Referenced::Message(v) => &v.name, |
55 | | } |
56 | 37 | } |
57 | | } |
58 | | |
59 | | impl PtrKey for Referenced { |
60 | 63 | fn ptr_key(&self) -> usize { |
61 | 63 | match self { |
62 | 54 | Referenced::Struct(v) => v.ptr_key(), |
63 | 9 | Referenced::Message(v) => v.ptr_key(), |
64 | | } |
65 | 63 | } |
66 | | } |
67 | | |
68 | | impl Referenced { |
69 | 180 | pub fn lookup(proto: &Protocol, reference_name: &str) -> Option<Self> { |
70 | 180 | proto |
71 | 180 | .structs |
72 | 180 | .get(reference_name) |
73 | 180 | .map(|v| Referenced::Struct(v117 .clone117 ())) |
74 | 180 | .or_else(|| proto.messages63 .get63 (reference_name63 ).map63 (|v| Referenced::Message(v63 .clone63 ()))) |
75 | 180 | } |
76 | | } |
77 | | |
78 | | #[derive(Clone, Debug)] |
79 | | pub struct FixedContainerField { |
80 | | pub ty: FixedFieldType, |
81 | | pub item_type: Rc<Structure>, |
82 | | } |
83 | | |
84 | | impl Display for FixedContainerField { |
85 | 10 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |
86 | 10 | write!(f, "FixedContainer<{}, Len = {}>", self.item_type.name, self.ty) |
87 | 10 | } |
88 | | } |
89 | | |
90 | | #[derive(Clone, Debug)] |
91 | | pub struct SizedBufferField { |
92 | | pub ty: FixedFieldType, |
93 | | } |
94 | | |
95 | | impl Display for SizedBufferField { |
96 | 14 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |
97 | 14 | write!(f, "Varbuf<{}>", self.ty) |
98 | 14 | } |
99 | | } |
100 | | |
101 | | #[derive(Clone, Debug)] |
102 | | pub struct ContainerField { |
103 | | pub ty: FixedFieldType, |
104 | | pub item_type: Rc<Message>, |
105 | | pub nested: bool, |
106 | | } |
107 | | |
108 | | impl Display for ContainerField { |
109 | 25 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |
110 | 25 | write!(f, "Container<{}, Len = {}>", self.item_type.name(), self.ty) |
111 | 25 | } |
112 | | } |
113 | | |
114 | | #[derive(Clone, Debug)] |
115 | | pub struct SizedContainerField { |
116 | | pub ty: FixedFieldType, |
117 | | pub item_type: Rc<Message>, |
118 | | pub size_ty: FixedFieldType, |
119 | | } |
120 | | |
121 | | impl Display for SizedContainerField { |
122 | 9 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |
123 | 9 | write!( |
124 | 9 | f, |
125 | 9 | "SizedContainer<{}, Len = {}, Size = {}>", |
126 | 9 | self.item_type.name(), |
127 | | self.ty, |
128 | | self.size_ty |
129 | | ) |
130 | 9 | } |
131 | | } |
132 | | |
133 | | #[derive(Clone, Debug)] |
134 | | pub struct FixedField { |
135 | | pub ty: FixedFieldType, |
136 | | } |
137 | | |
138 | | impl Display for FixedField { |
139 | 8 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |
140 | 8 | write!(f, "{}", self.ty) |
141 | 8 | } |
142 | | } |
143 | | |
144 | | #[derive(Clone, Debug)] |
145 | | pub struct UnionField { |
146 | | pub r: Rc<Union>, |
147 | | } |
148 | | |
149 | | impl Display for UnionField { |
150 | 8 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |
151 | 8 | f.write_str(self.r.name()) |
152 | 8 | } |
153 | | } |
154 | | |
155 | | #[derive(Clone, Debug)] |
156 | | pub enum FieldType { |
157 | | Fixed(FixedField), |
158 | | Ref(Referenced), |
159 | | |
160 | | /// A buffer field is a field which has a known size which can be determined at runtime |
161 | | /// (ex: a null-terminated string). |
162 | | Buffer, |
163 | | |
164 | | /// A sized buffer field is a field which has a known size field based on a configurable type |
165 | | /// (ex: a Varchar). |
166 | | SizedBuffer(SizedBufferField), |
167 | | |
168 | | /// A fixed container is a container which can store only fixed size elements (structures). |
169 | | FixedContainer(FixedContainerField), |
170 | | |
171 | | Union(UnionField), |
172 | | |
173 | | /// A container can store dynamically sized elements. |
174 | | Container(ContainerField), |
175 | | |
176 | | /// A container which has an additional configurable size field to detect the size in bytes of |
177 | | /// the container. |
178 | | SizedContainer(SizedContainerField), |
179 | | |
180 | | Payload, |
181 | | } |
182 | | |
183 | | impl Display for FieldType { |
184 | 125 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |
185 | 125 | match self { |
186 | 8 | FieldType::Fixed(v) => v.fmt(f), |
187 | 29 | FieldType::Ref(v) => f.write_str(v.name()), |
188 | 22 | FieldType::Buffer => f.write_str("Buffer"), |
189 | 14 | FieldType::SizedBuffer(v) => v.fmt(f), |
190 | 10 | FieldType::FixedContainer(v) => v.fmt(f), |
191 | 8 | FieldType::Union(v) => v.fmt(f), |
192 | 25 | FieldType::Container(v) => v.fmt(f), |
193 | 9 | FieldType::SizedContainer(v) => v.fmt(f), |
194 | 0 | FieldType::Payload => f.write_str("Bytes"), |
195 | | } |
196 | 125 | } |
197 | | } |
198 | | |
199 | | impl FieldType { |
200 | 55 | pub fn is_message_reference(&self) -> bool { |
201 | 55 | match self { |
202 | 14 | FieldType::Ref(v) => match v { |
203 | 10 | Referenced::Struct(_) => false, |
204 | 4 | Referenced::Message(_) => true, |
205 | | }, |
206 | 41 | _ => false, |
207 | | } |
208 | 55 | } |
209 | | |
210 | 30 | pub fn is_union(&self) -> bool { |
211 | 30 | matches!16 (self, FieldType::Union(_)) |
212 | 30 | } |
213 | | |
214 | 69 | pub fn is_string(&self) -> bool { |
215 | 69 | matches!44 (self, FieldType::SizedBuffer(_) | FieldType::Buffer) |
216 | 69 | } |
217 | | } |
218 | | |
219 | | #[derive(Copy, Clone, Debug)] |
220 | | pub struct SizeInfo { |
221 | | pub is_dyn_sized: bool, |
222 | | pub is_element_dyn_sized: bool, |
223 | | } |
224 | | |
225 | | #[derive(Clone, Debug)] |
226 | | pub struct HeaderField { |
227 | | pub name: String, |
228 | | pub index: usize, |
229 | | } |
230 | | |
231 | | impl HeaderField { |
232 | 184 | fn from_model(header: Option<String>, fields: &[Field]) -> Result<(Option<Self>, Option<&Field>), Error> { |
233 | 184 | match header { |
234 | 28 | Some(header) => { |
235 | 28 | let (index27 , field27 ) = fields |
236 | 28 | .iter() |
237 | 28 | .enumerate() |
238 | 28 | .find_map(|(k, v)| if v.name == header27 { Some((k, v))27 } else { None0 }27 ) Branch (238:43): [True: 27, False: 0]
Branch (238:43): [Folded - Ignored]
|
239 | 28 | .ok_or(Error::UndefinedReference(header))?1 ; |
240 | 27 | let header = HeaderField { |
241 | 27 | index, |
242 | 27 | name: field.name.clone(), |
243 | 27 | }; |
244 | 27 | Ok((Some(header), Some(field))) |
245 | | } |
246 | 156 | None => Ok((None, None)), |
247 | | } |
248 | 184 | } |
249 | | } |
250 | | |
251 | | #[derive(Clone, Debug)] |
252 | | pub struct Field { |
253 | | pub name: String, |
254 | | pub header: Option<HeaderField>, |
255 | | pub ty: FieldType, |
256 | | pub optional: bool, |
257 | | pub size: SizeInfo, |
258 | | pub endianness: Endianness, |
259 | | pub description: Option<Description>, |
260 | | pub codec: Option<String>, |
261 | | } |
262 | | |
263 | | impl Display for Field { |
264 | 125 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |
265 | 125 | match (self.optional, &self.codec) { |
266 | 6 | (true, None) => write!(f, "{}: {}?, {} endian", self.name, self.ty, self.endianness), |
267 | 39 | (false, None) => write!(f, "{}: {}, {} endian", self.name, self.ty, self.endianness), |
268 | 15 | (true, Some(v)) => write!(f, "{}: {} ({})?, {} endian", self.name, v, self.ty, self.endianness), |
269 | 65 | (false, Some(v)) => write!(f, "{}: {} ({}), {} endian", self.name, v, self.ty, self.endianness), |
270 | | } |
271 | 125 | } |
272 | | } |
273 | | |
274 | | impl Field { |
275 | 279 | pub fn codec(&self) -> &str { |
276 | 279 | self.codec.as_deref().unwrap_or("base") |
277 | 279 | } |
278 | | |
279 | 186 | fn from_model( |
280 | 186 | proto: &Protocol, |
281 | 186 | unsorted: &[Field], |
282 | 186 | has_headers: bool, |
283 | 186 | value: crate::model::message::MessageField, |
284 | 186 | ) -> Result<Self, Error> { |
285 | 186 | if (value.value.is_none() && value.item_type48 .is_none48 ()) Branch (285:13): [True: 48, False: 138]
Branch (285:38): [True: 1, False: 47]
Branch (285:13): [Folded - Ignored]
Branch (285:38): [Folded - Ignored]
|
286 | 185 | || (value.value.is_some() && value.item_type138 .is_some138 ()) { Branch (286:17): [True: 138, False: 47]
Branch (286:42): [True: 1, False: 137]
Branch (286:17): [Folded - Ignored]
Branch (286:42): [Folded - Ignored]
|
287 | 2 | return Err(Error::BadFieldType); |
288 | 184 | } |
289 | 184 | let (header183 , header_field183 ) = HeaderField::from_model(value.header, unsorted)?1 ; |
290 | 183 | if let Some(field27 ) = header_field { Branch (290:16): [True: 27, False: 156]
Branch (290:16): [Folded - Ignored]
|
291 | 26 | match &field.ty { |
292 | 26 | FieldType::Ref(Referenced::Struct(v)) => v.set_used_in_header(), |
293 | 1 | v => { |
294 | 1 | error!( |
295 | 1 | "Invalid header field type, expected struct reference, got field type {:?}", |
296 | | v |
297 | | ); |
298 | 1 | return Err(Error::InvalidHeaderType); |
299 | | } |
300 | | } |
301 | 156 | } |
302 | 182 | let builder = FieldBuilder::new(value.name, value.optional.unwrap_or_default(), proto.endianness) |
303 | 182 | .description(value.description) |
304 | 182 | .header(header) |
305 | 182 | .codec(value.codec); |
306 | 182 | if let Some(info135 ) = value.value { Branch (306:16): [True: 135, False: 47]
Branch (306:16): [Folded - Ignored]
|
307 | 135 | match info { |
308 | | MessageFieldValue::List { |
309 | 44 | max_len, |
310 | 44 | item_type, |
311 | 44 | max_size, |
312 | 44 | nested, |
313 | | } => { |
314 | 44 | if max_len == 0 { Branch (314:24): [True: 1, False: 43]
Branch (314:24): [Folded - Ignored]
|
315 | 1 | return Err(Error::ZeroArray); |
316 | 43 | } |
317 | 43 | if builder.has_codec() { Branch (317:24): [True: 0, False: 43]
Branch (317:24): [Folded - Ignored]
|
318 | 0 | return Err(Error::ForbiddenCodec(builder.name().into())); |
319 | 43 | } |
320 | 43 | let r = Referenced::lookup(proto, &item_type).ok_or(Error::UndefinedReference(item_type))?0 ; |
321 | 43 | let ty = FixedFieldType::from_max_value(max_len)?0 ; |
322 | 43 | match r { |
323 | 12 | Referenced::Struct(item_type) => Ok(builder |
324 | 12 | .codec(Some("list".into())) |
325 | 12 | .build(FieldType::FixedContainer(FixedContainerField { item_type, ty }))), |
326 | 31 | Referenced::Message(item_type) => { |
327 | 31 | if let Some(max_size7 ) = max_size { Branch (327:36): [True: 7, False: 24]
Branch (327:36): [Folded - Ignored]
|
328 | 7 | if max_size == 0 { Branch (328:36): [True: 1, False: 6]
Branch (328:36): [Folded - Ignored]
|
329 | 1 | return Err(Error::ZeroArray); |
330 | 6 | } |
331 | 6 | let size_ty = FixedFieldType::from_max_value(max_size)?0 ; |
332 | 6 | Ok(builder |
333 | 6 | .codec(Some("list".into())) |
334 | 6 | .size_info(SizeInfo { |
335 | 6 | is_element_dyn_sized: false, |
336 | 6 | is_dyn_sized: true, |
337 | 6 | }) |
338 | 6 | .build(FieldType::SizedContainer(SizedContainerField { |
339 | 6 | ty, |
340 | 6 | item_type, |
341 | 6 | size_ty, |
342 | 6 | }))) |
343 | | } else { |
344 | 24 | item_type.embedded.set(true); |
345 | 24 | Ok( |
346 | 24 | builder.codec(Some("list".into())).dynamic_size().build(FieldType::Container( |
347 | 24 | ContainerField { |
348 | 24 | ty, |
349 | 24 | item_type, |
350 | 24 | nested: nested.unwrap_or_default(), |
351 | 24 | }, |
352 | 24 | )), |
353 | 24 | ) |
354 | | } |
355 | | } |
356 | | } |
357 | | } |
358 | | MessageFieldValue::Container { |
359 | 12 | max_len, |
360 | 12 | item_type, |
361 | 12 | max_size, |
362 | 12 | nested, |
363 | | } => { |
364 | 12 | if max_len == 0 { Branch (364:24): [True: 0, False: 12]
Branch (364:24): [Folded - Ignored]
|
365 | 0 | return Err(Error::ZeroArray); |
366 | 12 | } |
367 | 12 | let r = Referenced::lookup(proto, &item_type).ok_or(Error::UndefinedReference(item_type))?0 ; |
368 | 12 | let ty = FixedFieldType::from_max_value(max_len)?0 ; |
369 | 12 | match r { |
370 | 0 | Referenced::Struct(item_type) => { |
371 | 0 | Ok(builder.build(FieldType::FixedContainer(FixedContainerField { item_type, ty }))) |
372 | | } |
373 | 12 | Referenced::Message(item_type) => { |
374 | 12 | if let Some(max_size6 ) = max_size { Branch (374:36): [True: 6, False: 6]
Branch (374:36): [Folded - Ignored]
|
375 | 6 | if max_size == 0 { Branch (375:36): [True: 0, False: 6]
Branch (375:36): [Folded - Ignored]
|
376 | 0 | return Err(Error::ZeroArray); |
377 | 6 | } |
378 | 6 | let size_ty = FixedFieldType::from_max_value(max_size)?0 ; |
379 | 6 | Ok(builder |
380 | 6 | .size_info(SizeInfo { |
381 | 6 | is_element_dyn_sized: false, |
382 | 6 | is_dyn_sized: true, |
383 | 6 | }) |
384 | 6 | .build(FieldType::SizedContainer(SizedContainerField { |
385 | 6 | ty, |
386 | 6 | item_type, |
387 | 6 | size_ty, |
388 | 6 | }))) |
389 | | } else { |
390 | 6 | item_type.embedded.set(true); |
391 | 6 | Ok(builder.dynamic_size().build(FieldType::Container(ContainerField { |
392 | 6 | ty, |
393 | 6 | item_type, |
394 | 6 | nested: nested.unwrap_or_default(), |
395 | 6 | }))) |
396 | | } |
397 | | } |
398 | | } |
399 | | } |
400 | 43 | MessageFieldValue::String { max_len } => { |
401 | 43 | if builder.has_codec() { Branch (401:24): [True: 0, False: 43]
Branch (401:24): [Folded - Ignored]
|
402 | 0 | return Err(Error::ForbiddenCodec(builder.name().into())); |
403 | 43 | } |
404 | 43 | match max_len { |
405 | 33 | None => Ok(builder.codec(Some("string".into())).build(FieldType::Buffer)), |
406 | 10 | Some(max_len) => { |
407 | 10 | if max_len == 0 { Branch (407:32): [True: 1, False: 9]
Branch (407:32): [Folded - Ignored]
|
408 | 1 | return Err(Error::ZeroArray); |
409 | 9 | } |
410 | 9 | let ty = FixedFieldType::from_max_value(max_len)?0 ; |
411 | 9 | Ok(builder |
412 | 9 | .codec(Some("string".into())) |
413 | 9 | .build(FieldType::SizedBuffer(SizedBufferField { ty }))) |
414 | | } |
415 | | } |
416 | | } |
417 | 12 | MessageFieldValue::Buffer { max_len } => match max_len { |
418 | 0 | None => Ok(builder.build(FieldType::Buffer)), |
419 | 12 | Some(max_len) => { |
420 | 12 | if max_len == 0 { Branch (420:28): [True: 0, False: 12]
Branch (420:28): [Folded - Ignored]
|
421 | 0 | return Err(Error::ZeroArray); |
422 | 12 | } |
423 | 12 | let ty = FixedFieldType::from_max_value(max_len)?0 ; |
424 | 12 | Ok(builder.build(FieldType::SizedBuffer(SizedBufferField { ty }))) |
425 | | } |
426 | | }, |
427 | 15 | MessageFieldValue::Union { name } => { |
428 | 15 | let r14 = proto.unions.get(&name).ok_or(Error::UndefinedReference(name))?1 ; |
429 | 14 | let header_field13 = header_field.ok_or(Error::MissingHeaderForUnion)?1 ; |
430 | 13 | match &header_field.ty { |
431 | 13 | FieldType::Ref(Referenced::Struct(v)) => { |
432 | 13 | if !Rc::ptr_eq(&r.discriminant.root, v) { Branch (432:32): [True: 1, False: 12]
Branch (432:32): [Folded - Ignored]
|
433 | 1 | error!( |
434 | 1 | "Union discriminant type mismatch, expected {}, got {}", |
435 | 1 | v.name, r.discriminant.root.name |
436 | | ); |
437 | 1 | return Err(Error::UnionTypeMismatch); |
438 | 12 | } |
439 | | } |
440 | 0 | _ => unreachable!(), |
441 | | } |
442 | 12 | if value.optional.unwrap_or_default() { Branch (442:24): [True: 0, False: 12]
Branch (442:24): [Folded - Ignored]
|
443 | 0 | eprintln!("WARNING: ignoring unsupported optional flag on union message field!"); |
444 | 12 | } |
445 | 12 | Ok(builder.size_info(r.size).build(FieldType::Union(UnionField { r: r.clone() }))) |
446 | | } |
447 | 0 | MessageFieldValue::Payload => Ok(builder.dynamic_size().build(FieldType::Payload)), |
448 | 9 | MessageFieldValue::Unsigned { bits } => { |
449 | 9 | let ty = FixedFieldType::from_model(StructFieldRaw::Unsigned { bits })?0 ; |
450 | 9 | Ok(builder.fixed_size().build(FieldType::Fixed(FixedField { ty }))) |
451 | | } |
452 | | } |
453 | | } else { |
454 | 47 | let item_type = unsafe { value.item_type.unwrap_unchecked() }; |
455 | 47 | let r = Referenced::lookup(proto, &item_type).ok_or(Error::UndefinedReference(item_type))?0 ; |
456 | 47 | match r { |
457 | 39 | Referenced::Struct(r) => { |
458 | 39 | let is_single = r.fields.len() == 1; |
459 | 39 | let is_fixed = r.fields[0].ty.as_fixed().is_some(); |
460 | 39 | let is_none = r.fields[0].ty.as_fixed().map(|v| v.raw.is_none()).unwrap_or_default(); |
461 | 39 | let is_byte_aligned = r.fields[0].loc.bit_size % 8 == 0; |
462 | 39 | trace!({has_headers} {is_single} {is_fixed} {is_none} {is_byte_aligned}, "Found struct reference: {}", r.name); |
463 | 39 | if !has_headers && is_single19 && is_fixed7 && is_none7 && is_byte_aligned7 { Branch (463:24): [True: 19, False: 20]
Branch (463:40): [True: 7, False: 12]
Branch (463:53): [True: 7, False: 0]
Branch (463:65): [True: 7, False: 0]
Branch (463:76): [True: 7, False: 0]
Branch (463:24): [Folded - Ignored]
Branch (463:40): [Folded - Ignored]
Branch (463:53): [Folded - Ignored]
Branch (463:65): [Folded - Ignored]
Branch (463:76): [Folded - Ignored]
|
464 | 7 | let fixed = unsafe { r.fields[0].ty.as_fixed().unwrap_unchecked() }; |
465 | 7 | Ok(builder.fixed_size().build(FieldType::Fixed(FixedField { ty: fixed.bits_type }))) |
466 | | } else { |
467 | 32 | Ok(builder.fixed_size().build(FieldType::Ref(Referenced::Struct(r)))) |
468 | | } |
469 | | } |
470 | 8 | Referenced::Message(r) => Ok(builder.size_info(r.size).build(FieldType::Ref(Referenced::Message(r)))), |
471 | | } |
472 | | } |
473 | 186 | } |
474 | | } |
475 | | |
476 | | #[derive(Clone, Debug)] |
477 | | pub struct Message { |
478 | | pub name: String, |
479 | | pub ty: Option<String>, |
480 | | pub description: Option<Description>, |
481 | | pub fields: Vec<Field>, |
482 | | pub size: SizeInfo, |
483 | | embedded: Cell<bool>, |
484 | | } |
485 | | |
486 | | impl Message { |
487 | 100 | pub(crate) fn is_embedded(&self) -> bool { |
488 | 100 | self.embedded.get() |
489 | 100 | } |
490 | | |
491 | 111 | pub fn from_model(proto: &Protocol, value: crate::model::message::Message) -> Result<Message, Error> { |
492 | 111 | let mut fields = Vec::with_capacity(value.fields.len()); |
493 | 111 | let mut dyn_sized_elem_count = 0; |
494 | 111 | let mut is_dyn_sized = false; |
495 | 180 | let has_headers111 = value.fields.iter()111 .any111 (|v| v.header.is_some()); |
496 | 287 | for v186 in value.fields { |
497 | 186 | let field176 = Field::from_model(proto, &fields, has_headers, v)?10 ; |
498 | 176 | if field.size.is_dyn_sized { Branch (498:16): [True: 128, False: 48]
Branch (498:16): [Folded - Ignored]
|
499 | 128 | is_dyn_sized = true; |
500 | 128 | }48 |
501 | 176 | if value.ty.is_none() && dyn_sized_elem_count > 0 && (field.size.is_dyn_sized0 || field.size.is_element_dyn_sized0 ) { Branch (501:16): [True: 176, False: 0]
Branch (501:38): [True: 0, False: 176]
Branch (501:67): [True: 0, False: 0]
Branch (501:94): [True: 0, False: 0]
Branch (501:16): [Folded - Ignored]
Branch (501:38): [Folded - Ignored]
Branch (501:67): [Folded - Ignored]
Branch (501:94): [Folded - Ignored]
|
502 | 0 | return Err(Error::VarsizeAfterPayload); |
503 | 176 | } |
504 | 176 | if field.size.is_element_dyn_sized { Branch (504:16): [True: 30, False: 146]
Branch (504:16): [Folded - Ignored]
|
505 | 30 | dyn_sized_elem_count += 1; |
506 | 146 | } |
507 | 176 | if value.ty.is_none() && dyn_sized_elem_count > 1 { Branch (507:16): [True: 176, False: 0]
Branch (507:38): [True: 0, False: 176]
Branch (507:16): [Folded - Ignored]
Branch (507:38): [Folded - Ignored]
|
508 | 0 | return Err(Error::MultiPayload); |
509 | 176 | } |
510 | 176 | fields.push(field); |
511 | | } |
512 | 101 | Ok(Message { |
513 | 101 | name: value.name, |
514 | 101 | ty: value.ty, |
515 | 101 | description: value.description, |
516 | 101 | fields, |
517 | 101 | size: SizeInfo { |
518 | 101 | is_dyn_sized, |
519 | 101 | is_element_dyn_sized: dyn_sized_elem_count > 0, |
520 | 101 | }, |
521 | 101 | embedded: Cell::new(false), |
522 | 101 | }) |
523 | 111 | } |
524 | | } |
525 | | |
526 | | name_index!(Message => name); |